package k8s

import (
	"context"
	"fmt"

	corev1 "k8s.io/api/core/v1"
	"k8s.io/apimachinery/pkg/api/errors"
	metav1 "k8s.io/apimachinery/pkg/apis/meta/v1"
	"k8s.io/apimachinery/pkg/labels"
)

func (k *K8sClient) ListServicesByLabels(namespace string, labelsMap map[string]string) ([]corev1.Service, error) {
	options := metav1.ListOptions{
		LabelSelector: labels.SelectorFromSet(labels.Set(labelsMap)).String(),
	}

	svcsList, err := k.Clientset.CoreV1().Services(namespace).List(context.TODO(), options)
	if err != nil {
		return nil, err
	}

	return svcsList.Items, nil
}

func (k *K8sClient) DeleteServicesByLabels(namespace string, labelsMap map[string]string, gracePeriod int) error {
	svcs, err := k.ListServicesByLabels(namespace, labelsMap)
	if err != nil {
		return err
	}

	gracePeriodSeconds := int64(gracePeriod)
	deleteOpts := metav1.DeleteOptions{
		GracePeriodSeconds: &gracePeriodSeconds,
	}

	var errs error
	for _, svc := range svcs {
		err := k.Clientset.CoreV1().Services(namespace).Delete(context.TODO(), svc.Name, deleteOpts)
		// TODO: use error wrap
		if err != nil {
			errs = fmt.Errorf("delete services by labels failed, err: %v, labels: %v", err, labelsMap)
		}
	}

	return errs
}

func (k *K8sClient) CreateService(service *corev1.Service) (*corev1.Service, error) {
	return k.Clientset.CoreV1().Services(service.Namespace).Create(context.TODO(), service, metav1.CreateOptions{})
}

func (k *K8sClient) CreateOrUpdateService(service *corev1.Service) (*corev1.Service, error) {
	old, err := k.Clientset.CoreV1().Services(service.Namespace).Get(context.TODO(), service.Name, metav1.GetOptions{})
	if err == nil {
		// TODO equal
		if service.ResourceVersion == "" {
			service.ResourceVersion = old.ResourceVersion
		}
		return k.Clientset.CoreV1().Services(service.Namespace).Update(context.TODO(), service, metav1.UpdateOptions{})
	}

	new, err := k.CreateService(service)
	if errors.IsAlreadyExists(err) {
		return k.CreateOrUpdateService(service)
	}

	return new, err
}
